package sync

import (
	"runtime"
	"time"

	"gitee.com/yrwy/msgo/pkg/errors"
)

//同步执行
type Waiter struct {
	ch chan struct{}
}

func NewWaiter() *Waiter {
	w := &Waiter{
		ch: make(chan struct{}),
	}
	runtime.SetFinalizer(w, func(w *Waiter) {
		close(w.ch)
	})
	return w
}

func (w *Waiter) Close() (e error) {
	defer func() {
		if p := recover(); p != nil {
			e = errors.ErrClosed
		}
	}()
	close(w.ch)
	return
}

func (w *Waiter) Recv() <-chan struct{} {
	return w.ch
}

func (w *Waiter) Send() chan<- struct{} {
	return w.ch
}

func (w *Waiter) WaitRecv() {
	<-w.ch
}

func (w *Waiter) WaitSend() {
	w.ch <- struct{}{}
}

//尝试读
func (w *Waiter) TryRecv() bool {
	select {
	case <-w.ch:
		return true
	default:
	}
	return false
}

//尝试写
func (w *Waiter) TrySend() bool {
	select {
	case w.ch <- struct{}{}:
		return true
	default:
	}
	return false
}

//成功收到信号返回true，超时返回false
func (w *Waiter) TimedRecv(dur time.Duration) bool {
	timer := time.NewTimer(dur)
	defer timer.Stop()
	select {
	case <-w.ch:
		return true
	case <-timer.C:
	}
	return false
}

//成功发送信号返回true，超时返回false
func (w *Waiter) TimedSend(dur time.Duration) bool {
	timer := time.NewTimer(dur)
	defer timer.Stop()
	select {
	case w.ch <- struct{}{}:
		return true
	case <-timer.C:
	}
	return false
}
